package de.tum.in.eist.poll.client;




import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

import de.tum.in.eist.poll.client.Model.Feedback;
import de.tum.in.eist.poll.client.Model.Lecture;


public class EIST_POLL implements EntryPoint {
		
	// Callback object
	private PollServiceAsync pollSvc = GWT.create(PollService.class);
	
	private String user = "";
	
	private abstract class MainPanel extends VerticalPanel{
		abstract public void refresh();
	}
	/**Sets up the Interface (UI) of the Poll
	 * Five vote buttons (RadioButton rb0-rb4) to vote how satisfied the user is with the lecture
	 * Two textfields (Textarea "like"/"dislike"), where the user can comment the lecture.
	 * Only the Admin can read the input of the textareas.
	 *
	 */
	private class PollPanel extends MainPanel{
	    RadioButton rb0 = new RadioButton("rating", "Very unsatisfied");
	    RadioButton rb1 = new RadioButton("rating", "Unsatisfied");
	    RadioButton rb2 = new RadioButton("rating", "Neutral");
	    RadioButton rb3 = new RadioButton("rating", "Satisfied");
	    RadioButton rb4 = new RadioButton("rating", "Very Satisfied");
	    int rating = 1;
	    TextArea like = new TextArea();
	    TextArea dislike = new TextArea();
	    /**
	     * sets up the interface of the lecture the method gets deliverd.
	     * @param lecture: the lecture for which the UI is built.
	     */
	    public PollPanel(final Lecture lecture){
	    	this.add(new HTML("<h2>"+lecture.getSubject()+"</h2>"));
		    this.add(new HTML("<b>How satisfied are you with today's lecture?</b>"));
		    rb0.setValue(true);
		    rb0.addClickHandler(new ClickHandler(){public void onClick(ClickEvent event) {rating = 1;}});
		    rb1.addClickHandler(new ClickHandler(){public void onClick(ClickEvent event) {rating = 2;}});
		    rb2.addClickHandler(new ClickHandler(){public void onClick(ClickEvent event) {rating = 3;}});
		    rb3.addClickHandler(new ClickHandler(){public void onClick(ClickEvent event) {rating = 4;}});
		    rb4.addClickHandler(new ClickHandler(){public void onClick(ClickEvent event) {rating = 5;}});
			this.add(rb0);
			this.add(rb1);
			this.add(rb2);
			this.add(rb3);
			this.add(rb4);
		    this.add(new HTML("<br/><b>What did you like most?</b>"));
			this.add(like);
		    this.add(new HTML("<br/><b>What did you dislike or did not understand at all?</b>"));
			this.add(dislike);
			HorizontalPanel hp = new HorizontalPanel();
			 
		    hp.add(new Button("Discard & Back",new ClickHandler(){

				/**
				 * if button "Discard & Back" clicked goes back to the LectureList
				 */
				public void onClick(ClickEvent event) {
					showLectureList();
					
				}
				
			}));
		    hp.add(new Button("Submit",new ClickHandler(){

				/**
				 * if button "Submit" clicked sends information/input to the database.
				 */
				public void onClick(ClickEvent event) {
					// Create service proxy if null
					if (pollSvc == null) {
						pollSvc = GWT.create(PollService.class);
					}
					
					AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>() {

						
						public void onFailure(Throwable caught) {
							showPopup(caught.getMessage());
						}

						/**
						 * if the delivery is successful, show the results of the poll to the user, else show error-message
						 * @param b
						 */
						public void onSuccess(Boolean b) {
							if(b){
								showPollResults(lecture);
							}else{
								showPopup("An Error occured while processing. <br/>Please Try again later");
								showLectureList();
							}
								

						}
						
					};
					pollSvc.pushFeedbackForLecture(lecture, new Feedback(rating,like.getText(),dislike.getText(), lecture.getEncodedKey()), callback);
					
				}
				
			}));
			this.add(hp);
			this.setStyleName("gwt-PollPanel");
		}
		
		public void refresh() {
			// Do Nothing
			// there are no informations who could be changed
			
		}

	}
	/**
	 * Class for the UI of the single dynamic lecture cells
	 * 
	 *
	 */
	private class LectureListPanel extends MainPanel{
		LectureListPanel(){
			
			// Load dynamic lecture content
			
			// Create service proxy if null
			if (pollSvc == null) {
				pollSvc = GWT.create(PollService.class);
			}
			
			AsyncCallback<Lecture[]> callback = new AsyncCallback<Lecture[]>() {

				
				public void onFailure(Throwable caught) {
					showPopup(caught.getMessage());					
				}

				
				public void onSuccess(Lecture[] result) {
					printLectures(result);

				}
				
			};
			pollSvc.getLectures(callback);
		}
		
		// Handle callback
		/**
		 * Print out lecture cells
		 */
		private void printLectures(Lecture[] lects) {
			this.clear();
			// Print out lecture cells
			
			for (int i = 0; i < lects.length; i++) {
				final Lecture l = lects[i];
				HTML h;
				if (l.getOpen() && !l.getAlreadyVoted()){// Open
					h=new HTML("<div class=\"lectureCell\"><span class=\"head\">" + l.getSubject() + 
							"</span>" + l.getDate() + "<br/>Open</div>");
					h.addClickHandler(new ClickHandler(){
						
						public void onClick(ClickEvent event) {
							showPoll(l);
						}
					});
				}else{// Closed
					h=new HTML("<div class=\"lectureCell\"><span class=\"head\">" + l.getSubject() + 
							"</span>" + l.getDate() + "<br/>" + l.getFeedbacks().size() + " Votes</div>");
					h.addClickHandler(new ClickHandler(){
						
						public void onClick(ClickEvent event) {
							showPollResults(l);
						}
					});
				}
				this.add(h);
			}
		}

		/**
		 * refresh to show new created lectures
		 */
		public void refresh() {
			// Create service proxy if null
			if (pollSvc == null) {
				pollSvc = GWT.create(PollService.class);
			}
			
			AsyncCallback<Lecture[]> callback = new AsyncCallback<Lecture[]>() {

				
				public void onFailure(Throwable caught) {
					showPopup(caught.getMessage());					
				}

				
				public void onSuccess(Lecture[] result) {
					printLectures(result);

				}
				
			};
			pollSvc.getLectures(callback);
		}
	}
	/**
	 * Class for the UI of the results of the poll
	 * 
	 *
	 */
	private class PollResultsPanel extends MainPanel{
		Lecture thisLecture;
		PollResultsPanel(Lecture lecture){
			thisLecture = lecture;
			this.add(new HTML("<b>Results for "+lecture.getSubject()+":<b>"));
			int vote[] = new int[5];
			String voteTitle[] = {"Very unsatisfied","Unsatisfied","Neutral","Satisfied","Very satisfied"};
			for(Feedback feedback:lecture.getFeedbacks()){
					vote[feedback.getRating()-1]++;
			}
			if(lecture.getFeedbacks().size()==0){
				lecture.getFeedbacks().add(null);
			}
			for(int i=0;i<5;i++){
				this.add(new HTML(voteTitle[i]));
				this.add(new HTML("<div class=\"voteBar\" style=\"width:"+(vote[i]*350/lecture.getFeedbacks().size())+"px\"></div>" +
						"<div class=\"voteBarG\" style=\"width:"+(350-vote[i]*350/lecture.getFeedbacks().size())+"px;\"></div>" +
						vote[i]+" Vote(s)"));
			}
		    this.add(new Button("Back",new ClickHandler(){

				
				public void onClick(ClickEvent event) {
					showLectureList();
					
				}
				
			}));
			this.setStyleName("gwt-PollResultsPanel");
		}

		/**
		 * refresh to get/show always the current results of the poll
		 */
		public void refresh() {
			AsyncCallback<Lecture[]> callback = new AsyncCallback<Lecture[]>() {

				
				public void onFailure(Throwable caught) {
					showPopup(caught.getMessage());					
				}

				
				public void onSuccess(Lecture[] result) {
					for(Lecture l:result){
						if(thisLecture.getEncodedKey().equals(l.getEncodedKey())){
							showPollResults(l);
						}
					}

				}
				
			};
			pollSvc.getLectures(callback);
			
		}
	}
	/**
	 * Class for the UI of the extended poll results, i.e. for the lecturer/admin
	 * to show him also the comments made by the voters in the two textareas "Like"/"Dislike"
	 *
	 */
	private class ExtendedPollResultsPanel extends MainPanel{
		
		Lecture thisLecture;
		
		ExtendedPollResultsPanel(Lecture lecture){
			thisLecture=lecture;
			this.add(new HTML("<b>Results for "+lecture.getSubject()+":<b>"));
			int vote[] = new int[5];
			String voteTitle[] = {"Very unsatisfied","Unsatisfied","Neutral","Satisfied","Very satisfied"};
			for(Feedback feedback:lecture.getFeedbacks()){
					vote[feedback.getRating()-1]++;
			}
			boolean noWrittenFeedbacks = false;
			if(lecture.getFeedbacks().size()==0){
				lecture.getFeedbacks().add(null);
				noWrittenFeedbacks = true;
				
			}
			for(int i=0;i<5;i++){
				this.add(new HTML(voteTitle[i]));
				this.add(new HTML("<div class=\"voteBar\" style=\"width:"+(vote[i]*350/lecture.getFeedbacks().size())+"px\"></div>" +
						"<div class=\"voteBarG\" style=\"width:"+(350-vote[i]*350/lecture.getFeedbacks().size())+"px;\"></div>" +
						vote[i]+" Vote(s)"));
			}
			if(!noWrittenFeedbacks)
				for(Feedback f:lecture.getFeedbacks()){
					VerticalPanel feedbackBox = new VerticalPanel();
					feedbackBox.setStyleName("feedbackBox");
					feedbackBox.add(new HTML("<b>Rating:</b>"+voteTitle[f.getRating()-1]));
					if(!f.getPositiveFeedback().equals("")){
						feedbackBox.add(new HTML("<b>Like:</b>"));
						feedbackBox.add(new HTML("<span class=\"posFB\">"+f.getPositiveFeedback()+"</span>"));
					}
					if(!f.getNegativeFeedback().equals("")){
						feedbackBox.add(new HTML("<b>Dislike:</b>"));
						feedbackBox.add(new HTML("<span class=\"negFB\">"+f.getNegativeFeedback()+"</span>"));
					}
					if(f.getNegativeFeedback().equals("")&&f.getPositiveFeedback().equals("")){
						feedbackBox.add(new HTML("<i>This User did not leave any written Feedback</i>"));
					}
					this.add(feedbackBox);
				}
		    this.add(new Button("Back",new ClickHandler(){

				
				public void onClick(ClickEvent event) {
					showEditableLectureList();
					
				}
				
			}));
			this.setStyleName("gwt-PollResultsPanel");
		}
		/**
		 * refresh to get/show always the current results of the poll
		 */
		public void refresh() {
			AsyncCallback<Lecture[]> callback = new AsyncCallback<Lecture[]>() {

				
				public void onFailure(Throwable caught) {
					showPopup(caught.getMessage());					
				}

				
				public void onSuccess(Lecture[] result) {
					for(Lecture l:result){
						if(thisLecture.getEncodedKey().equals(l.getEncodedKey())){
							showExtendedPollResults(l);
						}
					}

				}
				
			};
			pollSvc.getLectures(callback);
			
		}
	}
	/**
	 * Class for the UI of the login panel to create a loginbox and a password box
	 * and methods to compare/validate the input.
	 *
	 */
	private class LoginPanel extends HorizontalPanel{
		LoginPanel(){
			HTML t1 = new HTML("Login:");
			HTML t2 = new HTML("Password:");
			t1.setStyleName("login-text");
			t2.setStyleName("login-text");
			final TextBox tb = new TextBox();
			tb.setStyleName("");
			final PasswordTextBox ptb = new PasswordTextBox();
			ptb.setStyleName("");
			Button submit = new Button("Login",new ClickHandler(){

				
				public void onClick(ClickEvent event) {
					// Create service proxy if null
					if (pollSvc == null) {
						pollSvc = GWT.create(PollService.class);
					}
					
					AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>() {

						
						public void onFailure(Throwable caught) {
							showPopup(caught.getMessage());							
						}

						
						public void onSuccess(Boolean b) {
							if(b){
								user=tb.getText();
								showEditableLectureList(true);
							}else{
								showPopup("Couldn't log in.<br/>Maybe Login or Password are wrong");
							}
						}
						
					};
					pollSvc.checkCredentials(tb.getText(), ptb.getText(), callback);
				}
				
			});
			submit.setStyleName("");
			
			

			this.add(t1);
			this.add(tb);
			this.add(t2);
			this.add(ptb);
			this.add(submit);

			this.setStyleName("gwt-LoginPanel");
		}
	}
	/**
	 * Class to create a logout panel for an admin to logout
	 * 
	 *
	 */
	private class LogoutPanel extends HorizontalPanel{
		LogoutPanel(){
			HTML user = new HTML("Admin");
			user.setStyleName("login-text");
			Button submit = new Button("Logout",new ClickHandler(){

				
				public void onClick(ClickEvent event) {
					// Create service proxy if null
					if (pollSvc == null) {
						pollSvc = GWT.create(PollService.class);
					}
					
					AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>() {

						
						public void onFailure(Throwable caught) {
							showPopup(caught.getMessage());							
						}

					
						public void onSuccess(Boolean b) {
							if(!b)
								showLectureList(true);
							else
								showPopup("An Error occured while processing. <br/>You are still logged in. <br/>Please Try again later");


						}
						
					};
					pollSvc.checkCredentials("", "", callback);
					
				}
				
			});
			submit.setStyleName("");
			
			this.add(user);
			this.add(submit);
			this.setStyleName("gwt-LogoutPanel");

		}
	}
	/**
	 * Class to create two Popuppanel-Buttons "Yes" and "No" for different uses
	 * e.g. closing exception windows.
	 *
	 */
	private class PopupPanel extends VerticalPanel{

		ClickHandler closePopup = new ClickHandler(){

			
			public void onClick(ClickEvent event) {
				RootPanel.get("disableAll").setStyleName("hiddenPopup");
				RootPanel.get("popupPanel").setStyleName("hiddenPopup");
				
			}
			
		};
		
		public PopupPanel(String msg){
			this.add(new HTML(msg));
			this.add(new Button("Yes",closePopup));
		}
		
		public PopupPanel(String msg, ClickHandler ch) {
			this.add(new HTML(msg));
			HorizontalPanel vp = new HorizontalPanel();
			Button noButton = new Button("No");
			Button yesButton = new Button("Yes",ch);
			noButton.addClickHandler(closePopup);
			yesButton.addClickHandler(closePopup);
			vp.add(noButton);
			vp.add(yesButton);
			this.add(vp);
		}
		
	}
	/**
	 * Class that creates an UI, which can only be seen by a logged in user, who could
	 * open,delete,close lectures.
	 *
	 */
	private class EditableLectureListPanel extends MainPanel{
		EditableLectureListPanel(){
			
			AsyncCallback<Lecture[]> callback = new AsyncCallback<Lecture[]>() {

				
				public void onFailure(Throwable caught) {
					showPopup(caught.getMessage());					
				}

				
				public void onSuccess(Lecture[] result) {
					printLectures(result);

				}
				
			};
			pollSvc.getLectures(callback);
		}
		private void printLectures(Lecture[] lects){
			this.clear();
			VerticalPanel vp;
			HorizontalPanel hp;
			HTML html;
			ClickHandler newLectureHandler = new ClickHandler(){

				
				public void onClick(ClickEvent event) {
					showNewLecture();
					
				}
				
			};
			hp = new HorizontalPanel();
			hp.add(new Button("New Lecture",newLectureHandler));
			hp.setStyleName("editableLectureCell");
			this.add(hp);
			
			for (int i = 0; i < lects.length; i++) {
				final Lecture l = lects[i];

				vp = new VerticalPanel();
				hp= new HorizontalPanel();
				vp.setStyleName("editableLectureCell");
				html = new HTML(l.getSubject());
				html.setStyleName("head");
				vp.add(html);
				vp.add(new HTML(l.getDate()));
				vp.add(new HTML(l.getFeedbacks().size()+" Vote(s)"));
				if(l.getOpen())
					vp.add(new HTML("Open"));
				else
					vp.add(new HTML("Closed"));

				hp.add(new Button("Delete",new ClickHandler(){

					
					public void onClick(ClickEvent event) {
						showPopup("Do you really want to delete "+l.getSubject()+"?",new ClickHandler(){

							
							public void onClick(ClickEvent event) {
								pollSvc.deleteLecture(l, new AsyncCallback<Void>(){

									
									public void onFailure(Throwable caught) {
										showPopup(caught.getMessage());										
									}

									
									public void onSuccess(Void result) {
										showEditableLectureList();
										
									}
									
								});
								
							}
							
						});
						
					}
					
				}));
				hp.add(new Button("View Results",new ClickHandler(){

					
					public void onClick(ClickEvent event) {
						showExtendedPollResults(l);
						
					}
					
				}));
				if(l.getOpen())
					hp.add(new Button("Close",new ClickHandler(){

						
						public void onClick(ClickEvent event) {
							showPopup("Do you really want to close "+l.getSubject()+"?",new ClickHandler(){

								
								public void onClick(ClickEvent event) {
									pollSvc.closeLecture(l, new AsyncCallback<Void>(){

										
										public void onFailure(Throwable caught) {
											showPopup(caught.getMessage());											
										}

										
										public void onSuccess(Void result) {
											showEditableLectureList();
											
										}
										
									});
									
								}
								
							});
							
						}
						
					}));
				else
					hp.add(new Button("Open",new ClickHandler(){

						public void onClick(ClickEvent event) {
							showPopup("Do you really want to re-open "+l.getSubject()+"?",new ClickHandler(){

								
								public void onClick(ClickEvent event) {
									pollSvc.openLecture(l, new AsyncCallback<Void>(){

										
										public void onFailure(Throwable caught) {
											showPopup(caught.getMessage());											
										}

										
										public void onSuccess(Void result) {
											showEditableLectureList();
											
										}
										
									});
									
								}
								
							});
							
						}
						
					}));
				vp.add(hp);
				this.add(vp);
			}


			this.setStyleName("gwt-EditableLectureListPanel");
		}
		/**
		 * refresh to always get the current UI
		 */
		public void refresh() {
			AsyncCallback<Lecture[]> callback = new AsyncCallback<Lecture[]>() {

				
				public void onFailure(Throwable caught) {
					showPopup(caught.getMessage());					
				}

				
				public void onSuccess(Lecture[] result) {
					printLectures(result);

				}
				
			};
			pollSvc.getLectures(callback);
			
		}
	}
	/**
	 * Class to create the UI for adding a new lecture,
	 *  i.e. textfield for name of lecture and a add button.
	 *
	 */
	private class NewLecturePanel extends MainPanel{
		private TextBox tb;
		public NewLecturePanel(){
			this.add(new HTML("Add a new Lecture"));
			tb = new TextBox();
			this.add(tb);
			this.add(new Button("Add",new ClickHandler(){

				
				public void onClick(ClickEvent event) {
					// Create service proxy if null
					if (pollSvc == null) {
						pollSvc = GWT.create(PollService.class);
					}
					
					AsyncCallback<Void> callback = new AsyncCallback<Void>() {

						
						public void onFailure(Throwable caught) {
							showPopup(caught.getMessage());							
						}

						
						public void onSuccess(Void result) {
							showEditableLectureList();

						}
						
					};
//					Date date=new Date();
					pollSvc.addLecture(new Lecture(tb.getText(),user,true), callback);
					
				}
				
			}));
			
			this.setStyleName("gwt-NewLecturePanel");

		}
		
		
		public void refresh() {
			// Do Nothing
			// there are no informations who could be changed
			
		}
		
	}
	
	MainPanel mainPanel;
	/**
	 * base-frame for the interface, which loads all the classes above, dependent on the actions
	 * by the user.
	 */
	public void onModuleLoad() {
		mainPanel = new LectureListPanel();
		RootPanel.get("mainPanel").add(mainPanel);
		RootPanel.get("loginPanel").add(new LoginPanel());
		Scheduler.get().scheduleFixedDelay(new RepeatingCommand(){
			private int update=0;
			
			public boolean execute() {
				
				AsyncCallback<Integer> callback = new AsyncCallback<Integer>() {


					
					public void onFailure(Throwable caught) {
						showPopup(caught.getMessage());						
					}

					
					public void onSuccess(Integer result) {
						if(result>update){
							if(update>0)
								if(mainPanel!=null){
									System.out.println("refresh"+update);
									mainPanel.refresh();
								}else{
									System.out.println("no refresh"+update);
								}
							update=result;
						}

					}
					
				};
				pollSvc.getUpdate(callback);
				return true;
			}
			
		}, 50);
	}

	
	void showPollResults(Lecture lecture){
		RootPanel.get("mainPanel").clear();
		mainPanel = new PollResultsPanel(lecture);
		RootPanel.get("mainPanel").add(mainPanel);
	}
	
	void showPoll(Lecture lecture){
		RootPanel.get("mainPanel").clear();
		mainPanel = new PollPanel(lecture);
		RootPanel.get("mainPanel").add(mainPanel);
	}
	
	void showLectureList(){
		RootPanel.get("mainPanel").clear();
		mainPanel = new LectureListPanel();
		RootPanel.get("mainPanel").add(mainPanel);

	}

	void showLectureList(boolean logout){
		if(logout){
			RootPanel.get("loginPanel").clear();
			RootPanel.get("loginPanel").add(new LoginPanel());
		}
		showLectureList();
	}

	void showEditableLectureList(){
		RootPanel.get("mainPanel").clear();
		mainPanel = new EditableLectureListPanel();
		RootPanel.get("mainPanel").add(mainPanel);
	}
	
	void showEditableLectureList(boolean login){
		if(login){
			RootPanel.get("loginPanel").clear();
			RootPanel.get("loginPanel").add(new LogoutPanel());
		}
		showEditableLectureList();
	}

	void showExtendedPollResults(Lecture lecture){
		RootPanel.get("mainPanel").clear();
		mainPanel = new ExtendedPollResultsPanel(lecture);
		RootPanel.get("mainPanel").add(mainPanel);
	}
	
	void showNewLecture(){
		RootPanel.get("mainPanel").clear();
		mainPanel = new NewLecturePanel();
		RootPanel.get("mainPanel").add(mainPanel);
	}

	void showPopup(String msg,ClickHandler ch){
		RootPanel.get("disableAll").setStyleName("");
		RootPanel.get("popupPanel").setStyleName("");
		RootPanel.get("popupPanel").clear();
		RootPanel.get("popupPanel").add(new PopupPanel(msg,ch));
	}
	
	void showPopup(String msg){
		RootPanel.get("disableAll").setStyleName("");
		RootPanel.get("popupPanel").setStyleName("");
		RootPanel.get("popupPanel").clear();
		RootPanel.get("popupPanel").add(new PopupPanel(msg));
	}
	
}
